package cn.iocoder.yudao.module.scrm.controller.admin.customer;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.enums.ExcelColumn;
import cn.iocoder.yudao.framework.excel.core.strategy.DictTenantContext;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.scrm.annotations.EncryptPhoneNumbers;
import cn.iocoder.yudao.module.scrm.annotations.InterfaceDeleteValidator;
import cn.iocoder.yudao.module.scrm.controller.admin.clue.vo.ClueImportExcelVO;
import cn.iocoder.yudao.module.scrm.controller.admin.customer.vo.*;
import cn.iocoder.yudao.module.scrm.dal.dataobject.customer.CustomerDO;
import cn.iocoder.yudao.module.scrm.service.customer.CustomerService;
import cn.iocoder.yudao.module.scrm.service.customerassistants.CustomerAssistantsService;
import cn.iocoder.yudao.module.scrm.util.ImportTemplateRandomByTenant;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.scrm.enums.DictTypeConstants.*;
import static cn.iocoder.yudao.module.scrm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.scrm.enums.ErrorCodeConstants.CLUE_IMPORT_FORMAT_ERROR;
import static cn.iocoder.yudao.module.scrm.enums.common.CrmBizTypeEnum.CRM_CUSTOMER;
import static cn.iocoder.yudao.module.scrm.enums.common.CrmBizTypeEnum.CRM_CUSTOMER_RELEVANT_DATA;

@Tag(name = "管理后台 - SCRM客户")
@RestController
@RequestMapping("/scrm/customer")
@Validated
public class CustomerController {

    @Resource
    private CustomerService customerService;

    @Resource
    private CustomerAssistantsService customerAssistantsService;

    @Resource
    private DeptApi deptApi;
    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private DictDataApi dictDataApi;

    @Resource
    private PermissionApi permissionApi;

    @PostMapping("/create")
    @Operation(summary = "创建SCRM客户")
    @PreAuthorize("@ss.hasPermission('scrm:customer:create')")
    public CommonResult<Long> createCustomer(@Valid @RequestBody CustomerSaveReqVO createReqVO) {
        return success(customerService.createCustomer(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新SCRM客户")
    @PreAuthorize("@ss.hasPermission('scrm:customer:update')")
    public CommonResult<Boolean> updateCustomer(@Valid @RequestBody CustomerSaveReqVO updateReqVO) {
        customerService.updateCustomer(updateReqVO);
        return success(true);
    }

    @PutMapping("/update-deal-status")
    @Operation(summary = "更新客户的成交状态")
    @Parameters({@Parameter(name = "id", description = "客户编号", required = true), @Parameter(name = "dealStatus", description = "成交状态", required = true)})
    public CommonResult<Boolean> updateCustomerDealStatus(@RequestParam("id") Long id, @RequestParam("dealStatus") Boolean dealStatus) {
        customerService.updateCustomerDealStatus(id, dealStatus);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除SCRM客户")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('scrm:customer:delete')")
    @InterfaceDeleteValidator(tableType = CRM_CUSTOMER,strategyType = CRM_CUSTOMER_RELEVANT_DATA)
    public CommonResult<Boolean> deleteCustomer(@RequestParam("id") Long id) {
        customerService.deleteCustomer(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得SCRM客户")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('scrm:customer:query')")
    @EncryptPhoneNumbers
    public CommonResult<CustomerRespVO> getCustomer(@RequestParam("id") Long id) {
        // 获取客户信息
        CustomerDO customer = customerService.getCustomer(id);

        // 空值检查
        if (customer == null) {
            return success(null);
        }
        // 获取助手列表
        List<AdminUserRespDTO> assistantsList = customerAssistantsService.getCustomerAssistantsList(id);

        return CommonResult.success(buildCustomerDetail(customer).setAssistants(assistantsList));
    }

    @GetMapping("/page")
    @Operation(summary = "获得SCRM客户分页")
    @PreAuthorize("@ss.hasPermission('scrm:customer:query')")
    public CommonResult<PageResult<CustomerRespVO>> getCustomerPage(@Valid CustomerPageReqVO pageReqVO) {
        //如果是app端将wxId转为id
        if (pageReqVO.getAppOrPcType()) {
            List<Long> ids = adminUserApi.getUserListByWxIdsNotCheckDataPermission(pageReqVO.getOwnerUserIdString())
                    .getCheckedData().stream()
                    .map(AdminUserRespDTO::getId)
                    .collect(Collectors.toList());
            pageReqVO.setOwnerUserId(ids);
        }
        Long loginUserId = getLoginUserId();
        boolean isSuperAdmin = permissionApi.roleIsSuperAdmin(loginUserId).getCheckedData();

        // 设置客户归属
        setCustomerOwner(pageReqVO, loginUserId, isSuperAdmin);

        // 获取客户分页数据
        PageResult<CustomerDO> pageResult = customerService.getCustomerPage(pageReqVO);

        if (CollUtil.isEmpty(pageResult.getList())) {
            return success(PageResult.empty(pageResult.getTotal()));
        }

        // 拼接数据
        return success(new PageResult<>(buildCustomerDetailList(pageResult.getList()), pageResult.getTotal()));
    }

    /**
     * 设置客户归属逻辑
     */
    private void setCustomerOwner(CustomerPageReqVO pageReqVO, Long loginUserId, boolean isSuperAdmin) {
        if (Boolean.TRUE.equals(pageReqVO.getIsOwner())) {
            // 处理归属用户逻辑
            if (CollectionUtils.isAnyEmpty(pageReqVO.getOwnerUserId()) && Boolean.FALSE.equals(pageReqVO.getPool()) && !isSuperAdmin) {
                pageReqVO.setOwnerUserId(Collections.singletonList(loginUserId));
            }
        } else {
            // 协助人模式
            pageReqVO.setOwnerUserId(null);
            if (Boolean.FALSE.equals(pageReqVO.getPool()) && !isSuperAdmin) {
                pageReqVO.setAssistants(loginUserId);
            }
        }
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出SCRM客户或公海客户 Excel")
    @PreAuthorize("@ss.hasPermission('scrm:customer:export')")
    @OperateLog(type = EXPORT)
    public void exportCustomerExcel(@Valid CustomerPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<CustomerDO> list = customerService.getCustomerPage(pageReqVO).getList();
        // 导出 Excel
        ExcelUtils.write(response, "SCRM客户.xls", "数据", CustomerRespVO.class, buildCustomerDetailList(list));
    }

    @GetMapping("/get-import-template")
    @Operation(summary = "获得导入客户 Excel 模板")
    @PreAuthorize("@ss.hasPermission('scrm:customer:import:template')")
    public void importTemplate(HttpServletResponse response, @RequestHeader("Tenant-Id") Integer tenantId) throws IOException {
        // 手动创建导出 demo
        List<CustomerImportExcelVO> list = ImportTemplateRandomByTenant.getCustomerImportTemplateRandomByTenants();
        // 输出
        ExcelUtils.write(response, "客户导入模板.xls", "客户", CustomerImportExcelVO.class, list, builderSelectMap(tenantId));
    }

    //excel导出模板字典值下拉框
    private List<KeyValue<ExcelColumn, List<String>>> builderSelectMap(Integer tenantId) {
        DictTenantContext tenantContext = new DictTenantContext(tenantId);

        //查询字典中的值进行替换
        List<KeyValue<ExcelColumn, List<String>>> selectMap = new ArrayList<>();
        // 客户来源
        List<String> clientSourceList = tenantContext.getDictDataLabelList(SCRM_CLUE_CLIENT);
        selectMap.add(new KeyValue<>(ExcelColumn.F, clientSourceList));
        // 信息来源
        List<String> infoSourceList = tenantContext.getDictDataLabelList(SCRM_CLUE_INFO);
        selectMap.add(new KeyValue<>(ExcelColumn.H, infoSourceList));
        // 客户质量
        List<String> clientQualityList = dictDataApi.getDictDataLabelList(SCRM_CLUE_IDEA);
        selectMap.add(new KeyValue<>(ExcelColumn.I, clientQualityList));
        // 客户等级
        List<String> clueStateList = dictDataApi.getDictDataLabelList(SCRM_CUSTOMER_LEVEL);
        selectMap.add(new KeyValue<>(ExcelColumn.J, clueStateList));

        // 客户阶段
        List<String>  customerStageList = tenantContext.getDictDataLabelList(SCRM_CUSTOMER_STAGE);
        selectMap.add(new KeyValue<>(ExcelColumn.L, customerStageList));
        // 年营业额
        List<String>  yearTurnoverList = tenantContext.getDictDataLabelList(SCRM_YEAR_TURNOVER);
        selectMap.add(new KeyValue<>(ExcelColumn.M, yearTurnoverList));
        // 分公司
        List<String>  sonCompanyList = tenantContext.getDictDataLabelList(SCRM_SON_COMPANY);
        selectMap.add(new KeyValue<>(ExcelColumn.N, sonCompanyList));
        // 分公司
        List<String>   paymentMethodList = tenantContext.getDictDataLabelList(SCRM_PAYMENT_METHOD);
        selectMap.add(new KeyValue<>(ExcelColumn.O, paymentMethodList));
        // 峰会是否签到
        List<String> summitStatusNameList = tenantContext.getDictDataLabelList(SCRM_SUMMIT_STATUS);
        selectMap.add(new KeyValue<>(ExcelColumn.P, summitStatusNameList));
        return selectMap;
    }


    @PostMapping("/import")
    @Operation(summary = "批量导入客户或者公海 Excel")
    @Parameters({@Parameter(name = "file", description = "Excel 文件", required = true), @Parameter(name = "updateSupport", description = "是否支持更新，默认为 false", example = "true")})
    @PreAuthorize("@ss.hasPermission('scrm:customer:import')")
    public CommonResult<CustomerImportExcelRespVO> importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport, @RequestParam(value = "clientOrPool", required = false, defaultValue = "true") Boolean clientOrPool) throws Exception {

        try {
            if (file == null || file.isEmpty()) {
                throw exception(CUSTOMER_IMPORT_NOT_IS_EMPTY); // 文件为空异常
            }
            // 读取Excel文件并转换为 ClueImportExcelVO 列表
            List<CustomerImportExcelVO> list = ExcelUtils.readNotNull(file, CustomerImportExcelVO.class);
            // 调用业务逻辑进行添加
            return success(customerService.importCustomerListNotCanUpdate(list));
        } catch (IOException | IllegalArgumentException e) {
            // 捕获文件读取和格式异常
            throw exception(CUSTOMER_IMPORT_FORMAT_ERROR);
        } catch (Exception e) {
            // 捕获其他异常
            throw exception(CUSTOMER_IMPORT_FORMAT_ERROR);
        }
    }


    @PutMapping("/updateOwner")
    @Operation(summary = "更新SCRM客户负责人-转移客户")
    @PreAuthorize("@ss.hasPermission('scrm:customer:updateOwner')")
    public CommonResult<Boolean> transferCustomer(@Valid @RequestBody TransferCustomerReqVO reqVO) {
        if (reqVO.getUserId() == null && StringUtils.isBlank(reqVO.getWxId())) {
            return error(CUSTOMER_TRANSFER_NOT_NULL);
        }
        customerService.transferCustomer(reqVO);
        return success(true);
    }

    private CustomerRespVO buildCustomerDetail(CustomerDO customerDO) {
        if (customerDO == null) {
            return null;
        }
        return buildCustomerDetailList(Collections.singletonList(customerDO)).get(0);
    }


    public List<CustomerRespVO> buildCustomerDetailList(List<CustomerDO> list) {
        if (CollUtil.isEmpty(list)) {
            return java.util.Collections.emptyList();
        }
        // 1.1 获取创建人、负责人列表
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapNotCheckDataPermission(convertListByFlatMap(list, contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMapNotCheckDataPermission(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
        // 2. 转换成 VO
        return BeanUtils.toBean(list, CustomerRespVO.class, customerVO -> {
            // 2.1 设置创建人、负责人名称
            MapUtils.findAndThen(userMap, NumberUtils.parseLong(customerVO.getCreator()), user -> customerVO.setCreatorName(user.getNickname()));
            MapUtils.findAndThen(userMap, customerVO.getOwnerUserId(), user -> {
                customerVO.setOwnerUserName(user.getNickname());
                MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> customerVO.setOwnerUserDeptName(dept.getName()));
            });
        });
    }

    @PutMapping("/put-pool")
    @Operation(summary = "数据放入公海")
    @Parameter(name = "ids", description = "客户编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('scrm:customer:update:putPool')")
    public CommonResult<Boolean> putCustomerPool(@RequestParam("ids") List<Long> ids) {
        ids.forEach(id -> customerService.putCustomerPool(id));
        return success(true);
    }

    @PutMapping("/receive")
    @Operation(summary = "领取公海客户")
    @Parameter(name = "ids", description = "编号数组", required = true, example = "1,2,3")
    @PreAuthorize("@ss.hasPermission('scrm:customer:receive')")
    public CommonResult<Boolean> receiveCustomer(@RequestParam(value = "ids") List<Long> ids) {
        customerService.receiveCustomer(ids, getLoginUserId(), Boolean.TRUE);
        return success(true);
    }

    @PutMapping("/distribute")
    @Operation(summary = "分配公海给对应负责人")
    @PreAuthorize("@ss.hasPermission('crm:customer:distribute')")
    public CommonResult<Boolean> distributeCustomer(@Valid @RequestBody CustomerDistributeReqVO distributeReqVO) {
        customerService.receiveCustomer(distributeReqVO.getIds(), distributeReqVO.getOwnerUserId(), Boolean.FALSE);
        return success(true);
    }



    @PutMapping("/lock")
    @Operation(summary = "锁定/解锁客户")
    @PreAuthorize("@ss.hasPermission('scrm:customer:lock')")
    public CommonResult<Boolean> lockCustomer(@Valid @RequestBody CustomerLockReqVO lockReqVO) {
        customerService.lockCustomer(lockReqVO, getLoginUserId());
        return success(true);
    }

}